<?php
/**
 * 数据库操作类
 * User: kang
 * Date: 2019-12-16
 * Time: 21:00
 */

namespace mylibrary;

use \think\facade\Db;

class Database
{
    public $map=[];
    public $mapOr=[];
    public $mapWhere=[];
    public $order=[];
    public $field=true;
    public $group='';
    public $having='';
    public $model;
    public $limit=20;

    public $data=[];

    /*
     * 等于
     * */
    public function map_eq($field,$value){
        $this->map[]=[$field,'=',$value];
    }
    /*
     * 不等于
     * */
    public function map_neq($field,$value){
        $this->map[]=[$field,'<>',$value];
    }
    /*
     * 大于
     * */
    public function map_gt($field,$value){
        $this->map[]=[$field,'>',$value];
    }
    /*
     * 大于等于
     * */
    public function map_egt($field,$value){
        $this->map[]=[$field,'>=',$value];
    }
    /*
     * 小于
     * */
    public function map_lt($field,$value){
        $this->map[]=[$field,'<',$value];
    }
    /*
     * 小于等于
     * */
    public function map_elt($field,$value){
        $this->map[]=[$field,'<=',$value];
    }
    /*
     * 模糊查询
     * */
    public function map_like($field,$value){
        $this->map[]=[$field,'like','%'.$value.'%'];
    }
    /*
     * 模糊查询排除
     * */
    public function map_not_like($field,$value){
        $this->map[]=[$field,'not like','%'.$value.'%'];
    }
    /*
     * 区间查询
     * */
    public function map_between($field,$value){
        $this->map[]=[$field,'between',$value];
    }
    /*
     * 非区间查询
     * */
    public function map_not_between($field,$value){
        $this->map[]=[$field,'not between',$value];
    }
    /*
     * IN查询
     * */
    public function map_in($field,$value){
        $this->map[]=[$field,'in',$value];
    }
    /*
     * NOT IN查询
     * */
    public function map_not_in($field,$value){
        $this->map[]=[$field,'not in',$value];
    }
    /*
     * 表达式查询
     * */
    public function map_exp($field,$value){
        $this->map[]=[$field,'exp',$value];
    }

    /*
     * 或查询
     * */
    public function map_or($map_array=[]){
        $this->mapOr=$map_array;
    }
    /*
     * 获取所有条件
     * */
    public function default_map(){
        $key_field=[];
        foreach ($this->map as $key => $value) {
            $key_field[]=$value[0];
        }
        /*默认查询未删除数据*/
        if(!in_array("is_del",$key_field)){
            $this->map[] =['is_del','=',0];
        }
        /*除了后台，默认查询未禁用数据*/
        if((app('http')->getName() != 'backend') && !in_array("is_del",$key_field)){
            $this->map[] =['is_hid','=',0];
        }
    }
    /*
     * 降序
     * */
    public function order_desc($field){
        $this->order[$field]='desc';
    }
    /*
     * 升序
     * */
    public function order_asc($field){
        $this->order[$field]='asc';
    }

    /**
     *  获取数据集
     *  @param $model   表名[不需要前缀]或表模型[格式：应用/模型名称]
     */
    public function select($model) {
        if(strpos($model,'/')){
            $model_arr=explode("/",$model);
            $class = '\\app\\'.$model_arr[0].'\\model\\'.$model_arr[1];
            $db_model=new $class;
        }else{
            $db_model=Db::name($model);
        }
        $this->default_map();
        $db_model->where($this->map);
        $mapOr=$this->mapOr;
        if($mapOr){
            $db_model->where(function ($query) use ($mapOr){
                $query->whereOr($mapOr);
            });
        }
        if($this->mapWhere){
            $db_model->where($this->mapWhere);
        }
        return $db_model->field($this->field)->strict(false)->order($this->order)->group($this->group)->having($this->having)->select();
    }
    /**
     *  查询某个字段的值可以用
     *  @param $model   表名[不需要前缀]或表模型[格式：应用/模型名称]
     *  @param $field   查询某一列的值
     */
    public function value($model,$field) {
        if(strpos($model,'/')){
            $model_arr=explode("/",$model);
            $class = '\\app\\'.$model_arr[0].'\\model\\'.$model_arr[1];
            $db_model=new $class;
        }else{
            $db_model=Db::name($model);
        }
        $this->default_map();
        $db_model->where($this->map);
        $mapOr=$this->mapOr;
        if($mapOr){
            $db_model->where(function ($query) use ($mapOr){
                $query->whereOr($mapOr);
            });
        }

        if($this->mapWhere){
            $db_model->where($this->mapWhere);
        }
        return $db_model->field($this->field)->strict(false)->order($this->order)->group($this->group)->having($this->having)->value($field);
    }
    /**
     *  查询某一列的值可以用
     *  @param $model   表名[不需要前缀]或表模型[格式：应用/模型名称]
     *  @param $field   查询某一列的值
     *  @param $key     查询某一列的索引值
     */
    public function column($model,$field,$key) {
        if(strpos($model,'/')){
            $model_arr=explode("/",$model);
            $class = '\\app\\'.$model_arr[0].'\\model\\'.$model_arr[1];
            $db_model=new $class;
        }else{
            $db_model=Db::name($model);
        }
        $this->default_map();
        $db_model->where($this->map);
        $mapOr=$this->mapOr;
        if($mapOr){
            $db_model->where(function ($query) use ($mapOr){
                $query->whereOr($mapOr);
            });
        }
        if($this->mapWhere){
            $db_model->where($this->mapWhere);
        }
        return $db_model->field($this->field)->strict(false)->order($this->order)->group($this->group)->having($this->having)->column($field,$key);
    }
    /**
     *  游标查询
     *  @param $model   表名[不需要前缀]或表模型[格式：应用/模型名称]
     */
    public function cursor($model) {
        if(strpos($model,'/')){
            $model_arr=explode("/",$model);
            $class = '\\app\\'.$model_arr[0].'\\model\\'.$model_arr[1];
            $db_model=new $class;
        }else{
            $db_model=Db::name($model);
        }
        $this->default_map();
        $db_model->where($this->map);
        $mapOr=$this->mapOr;
        if($mapOr){
            $db_model->where(function ($query) use ($mapOr){
                $query->whereOr($mapOr);
            });
        }
        if($this->mapWhere){
            $db_model->where($this->mapWhere);
        }
        return $db_model->field($this->field)->strict(false)->order($this->order)->group($this->group)->having($this->having)->cursor();
    }
    /**
     *  获取数据集
     *  @param $model   表名[不需要前缀]或表模型[格式：应用/模型名称]
     */
    public function paginate($model) {
        if(strpos($model,'/')){
            $model_arr=explode("/",$model);
            $class = '\\app\\'.$model_arr[0].'\\model\\'.$model_arr[1];
            $db_model=new $class;
        }else{
            $db_model=Db::name($model);
        }
        $this->default_map();
        $mapOr=$this->mapOr;
        if($mapOr){
            $db_model->where(function ($query) use ($mapOr){
                $query->whereOr($mapOr);
            });
        }
        $db_model->where($this->map);
        if($this->mapWhere){
            $db_model->where($this->mapWhere);
        }
        $list=$db_model->field($this->field)->strict(false)->order($this->order)->group($this->group)->having($this->having)->paginate($this->limit);
        $data['list']=$list->items();
        $data['page']=$list->render();
        return $data;
    }
    /**
     *  获取单条数据
     *  @param $model   表名[不需要前缀]或表模型[格式：应用/模型名称]
     */
    public function find($model) {
        if(strpos($model,'/')){
            $model_arr=explode("/",$model);
            $class = '\\app\\'.$model_arr[0].'\\model\\'.$model_arr[1];
            $db_model=new $class;
        }else{
            $db_model=Db::name($model);
        }
        $this->default_map();
        $db_model->where($this->map);
        $mapOr=$this->mapOr;
        if($mapOr){
            $db_model->where(function ($query) use ($mapOr){
                $query->whereOr($mapOr);
            });
        }
        if($this->mapWhere){
            $db_model->where($this->mapWhere);
        }
        return $db_model->field($this->field)->order($this->order)->find();
    }
    /**
     * 添加、更新数据
     *  @param $Model   表模型
     *  @param $rules   查询规则
     *  @param $map 查询条件
     *  @param $data    数据
     */
    public function update($model) {
        if(strpos($model,'/')){
            $model_arr=explode("/",$model);
            $class = '\\app\\'.$model_arr[0].'\\model\\'.$model_arr[1];
            $db_model=new $class;
        }else{
            $db_model=Db::name($model);
        }
        $data=$this->data;
        foreach ($data as $key=>$row){
            if(strlen($row)==0){
                unset($data[$key]);
            }
        }
        if(empty($this->map) && !isset($data[$db_model->getPk()]) || ( isset($data[$db_model->getPk()]) && strlen($data[$db_model->getPk()])<=0 ) ) {
            unset($data[$db_model->getPk()]);
            $data['add_time'] = date("Y-m-d H:i:s");
            $data['update_time'] = date("Y-m-d H:i:s");
            //返回添加成功后的主键ID
            $result = $db_model->strict(false)->insertGetId($data);
        }else{
            $data['update_time'] = date("Y-m-d H:i:s");
            if(!empty($this->map)){
                //$this->map_eq($db_model->getPk(),$data[$db_model->getPk()]);
                $result = $db_model->strict(false)->where($this->map)->update($data);
            }else{
                //update 方法返回影响数据的条数，没修改任何数据返回 0
                $result = $db_model->strict(false)->update($data);
            }
            if(is_numeric($result) && empty($this->map)) {
                $result = $data['id'];
            }
        }
        /*执行更新后的回调函数*/
        $trace = debug_backtrace();
        if(isset($trace[1]['object']) && is_object($trace[1]['object']) && method_exists($trace[1]['object'],'call_back_change')){
            $trace[1]['object']->call_back_change();
        }

        return $result;
    }
    /**
     *  添加数据
     *  @param $model   表模型
     *  @param $map 条件
     *  @param $rules   验证
     */
    function add_data($model, $rules = array(), $map = array()) {
        if(strpos($model,'/')){
            $model_arr=explode("/",$model);
            $class = '\\app\\'.$model_arr[0].'\\model\\'.$model_arr[1];
            $db_model=new $class;
        }else{
            $db_model=Db::name($model);
        }
        $validate_rule=[];
        $validate_msg=[];
        foreach($rules as $row){
            $validate_rule[$row[0]]=$row[1];
            $validate_msg[$row[0].'.'.$row[1]]=$row[2];
        }
        $validate=new \think\Validate;
        $validate->rule($validate_rule)->message($validate_msg);
        $data=$this->data;
        if (!$validate->check($data)) {
            return $validate->getError();
        }
        //返回添加成功后的主键ID
        $result = $db_model->insertGetId($data);

        /*执行更新后的回调函数*/
        $trace = debug_backtrace();
        if(isset($trace[1]['object']) && is_object($trace[1]['object']) && is_callable([$trace[1]['object'],'call_back_change'],true)){
            $trace[1]['object']->call_back_change();
        }
        return $result;
    }
    /**
     *  删除数据
     *  @param $Model   表模型
     *  @param $map 条件
     */
    public function delete_data($model, $map = array()) {
        if(strpos($model,'/')){
            $model_arr=explode("/",$model);
            $class = '\\app\\'.$model_arr[0].'\\model\\'.$model_arr[1];
            $db_model=new $class;
        }else{
            $db_model=Db::name($model);
        }
        $db_model->where($this->map);
        $mapOr=$this->mapOr;
        if($mapOr){
            $db_model->where(function ($query) use ($mapOr){
                $query->whereOr($mapOr);
            });
        }
        if($this->mapWhere){
            $db_model->where($this->mapWhere);
        }
        $db_model->where($this->map)->delete();
        /*执行更新后的回调函数*/
        $trace = debug_backtrace();
        if(isset($trace[1]['object']) && is_object($trace[1]['object']) && method_exists([$trace[1]['object'],'call_back_change'],true)){
            $trace[1]['object']->call_back_change();
        }
        return true;
    }

    /**
     *  统计数据
     *  @param $Model   表模型
     *  @param $map 条件
     *  @param $field   字段
     */
    public function count_data($model) {
        if(strpos($model,'/')){
            $model_arr=explode("/",$model);
            $class = '\\app\\'.$model_arr[0].'\\model\\'.$model_arr[1];
            $db_model=new $class;
        }else{
            $db_model=Db::name($model);
        }
        $this->default_map();
        $db_model->where($this->map);
        $mapOr=$this->mapOr;
        if($mapOr){
            $db_model->where(function ($query) use ($mapOr){
                $query->whereOr($mapOr);
            });
        }
        if($this->mapWhere){
            $db_model->where($this->mapWhere);
        }
        return $db_model->group($this->group)->count($db_model->getPk());
    }
    /**
     * 更新后的回调函数
     * @return StringOperate 更新结果
     */
    public function call_back_change(){
        /*清除缓存*/
        if(property_exists($this,'table_cache')){
            $cache_name=$this->table_cache;
            if(is_array($cache_name)){
                foreach ($cache_name as $key => $val) {
                    cache($val,null);
                }
            }else{
                cache($cache_name,null);
            }
        }
        return true;
    }
}